package instance

import (
	"com.yy.api/common/logger"
	types "com.yy.api/common/pojo/models"
	cP "com.yy.api/common/pojo/param/container"
	"com.yy.api/common/pojo/result"
	cUtils "com.yy.api/common/utils"
	"com.yy.api/server/lib/containers"
	"sync"
)

// 对 rowImageOpt 做映射 -->
var rowImageMap = map[string]string{
	"nginx:latest": "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:latest",
	"redis:latest": "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/redis:latest",
	"mysql:latest": "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/mysql:latest",
	"CUDA 12.2 v2": "registry.cn-shanghai.aliyuncs.com/namespacetest2024/cu_12_2_base:1.1",
}

func (is *ServiceImpl) CreateInstance(opts map[string]string) (string, bool) {
	rowImageOpt, portMappingsOpt, gpuNumOpt, nameOpt, userIdOpt := opts["rowImage"], opts["portMappings"], opts["gpuNum"], opts["name"], opts["userId"]
	// 业务逻辑
	portMappingsParam := cP.ToParamPortMappings(portMappingsOpt)
	//hostPortList := getHostPortListFromPortMappings(portMappingsParam)
	gpuIdsParam, ok := gm.IsAvailable(cUtils.StrToInt(gpuNumOpt))

	defer gm.Acquire(gpuIdsParam)
	// 判断rowImageOpt是否在rowImageMap中
	rowImageParam, exists := rowImageMap[rowImageOpt]
	if !exists {
		is.Fail(result.NewJsonResult(result.AGENT_IMAGE_NOT_FOUND_ERROR, nil))
		return "", false
	}
	//if ok := containers.PullImage(rowImageParam); !ok {
	//	is.Fail(result.NewJsonResult(result.AGENT_PULL_IMAGE_ERROR, nil))
	//	return "", false
	//}
	// 检查本地镜像是否存在
	// 若不存在 尝试拉取镜像
	//if ok := cS.IsImageAvailable(rowImageOpt); !ok {
	//	if ok := cS.PullImage(rowImageOpt); !ok {
	//		ctrl.Fail(result.NewJsonResult(result.AGENT_PULL_IMAGE_ERROR, nil))
	//		return
	//	}
	//
	//}

	//**检查函数改写成异步形式
	// ---------------------------------------------------------------------------------
	//  创建容器
	cID, ok := containers.CreateContainer(rowImageParam, portMappingsParam, gpuIdsParam, nameOpt, userIdOpt)
	if !ok {
		is.Fail(result.NewJsonResult(result.AGENT_CREATE_CONTAINER_ERROR, nil))
		return "", false
	}
	// 启动容器
	if ok := containers.StartContainer(cID); !ok {
		is.Fail(result.NewJsonResult(result.AGENT_START_CONTAINER_ERROR, nil))
		return "", false
	}

	// -------------------------------------------------------------
	// 容器状态检测 改为异步形式
	// 获取容器信息
	//reslt, ok := containers.InspectContainer(cID)
	//if !ok {
	//	is.Fail(result.NewJsonResult(result.AGENT_INSPECT_CONTAINER_ERROR, nil))
	//	return "", false
	//}

	//cS.PersistImageInfoToDB(rowImageOpt)
	//cS.PersistContainerInfoToDB(userIdOpt, hostPortList, portMappingsParam, cID)
	// 服务处理成功，返回结果 <返回容器ID即可>
	return cID, true

}

var gm = NewGpuManager([]int{0, 1, 2, 3, 4, 5, 6, 7})

type CreateInstanceHelper struct {
	portMappingsParam []types.PortMapping
	hostPortList      []string
	gpuIdsParam       []int
}

func getHostPortListFromPortMappings(portMappings []types.PortMapping) []string {
	var hostPortList []string
	for _, portMapping := range portMappings {
		hostPortList = append(hostPortList, portMapping.HostPort)
	}
	return hostPortList
}

type GpuState struct {
	mu   sync.Mutex
	used bool
}
type GpuManager struct {
	mu   sync.Mutex
	gpus map[int]*GpuState
}

func NewGpuManager(total []int) *GpuManager {
	m := &GpuManager{
		gpus: make(map[int]*GpuState, len(total)),
	}
	for _, id := range total {
		m.gpus[id] = &GpuState{}
	}
	return m
}

func (g *GpuManager) Acquire(gpuIds []int) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	var acquired []int
	for _, id := range gpuIds {
		state, exists := g.gpus[id]
		if !exists {
			goto rollback
		}
		state.mu.Lock()
		if state.used {
			state.mu.Unlock()
			goto rollback
		}
		state.used = true
		state.mu.Unlock()
		acquired = append(acquired, id)
	}
	return true

rollback:
	for _, id := range acquired {
		if s, ok := g.gpus[id]; ok {
			s.mu.Lock()
			s.used = false
			s.mu.Unlock()
		}
	}
	return false
}

func (g *GpuManager) Release(gpuId int) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	state, exists := g.gpus[gpuId]
	if !exists {
		logger.Default.Errorf("gpu not exists! gpuId:%v", gpuId)
		return false
	}
	state.mu.Lock()
	defer state.mu.Unlock()

	if !state.used {
		logger.Default.Infof("Trying to release an unreleased GPU:%v", gpuId)
		return false
	}
	state.used = false
	logger.Default.Infof("Released GPU: %v", gpuId)
	return true
}

func (g *GpuManager) IsAvailable(gpuNum int) ([]int, bool) {
	g.mu.Lock()
	defer g.mu.Unlock()
	var available []int
	for id, state := range g.gpus {
		state.mu.Lock()
		if !state.used {
			available = append(available, id)
		}
		state.mu.Unlock()
	}
	if len(available) < gpuNum {
		logger.Default.Errorf("Not enough GPUs available. Need %d, but only %d available.", gpuNum, len(available))
		return []int{}, false
	}
	var acquired []int
	for i := 0; i < gpuNum; i++ {
		acquired = append(acquired, available[i])
	}
	return acquired, true
}
